using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace MyMedia.iPod.Music
{
	public class ITunesDB : Database
	{
		Root m_root;
		bool m_loaded;

		List<TrackItem> m_songs = new List<TrackItem>();
		List<string> m_artists = new List<string>();
		List<string> m_albums = new List<string>();
		Dictionary<string, List<string>> m_artistAlbum = new Dictionary<string, List<string>>(StringComparer.InvariantCultureIgnoreCase);
		Dictionary<string, List<TrackItem>> m_albumSongs = new Dictionary<string, List<TrackItem>>(StringComparer.InvariantCultureIgnoreCase);

		public ITunesDB() { }
		public ITunesDB(string fileName)
		{
			Load(fileName);
		}

		public override void Load(string fileName)
		{
			FileStream stream = null;
			try
			{
				stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
				using (BinaryReader reader = new BinaryReader(stream))
				{
					m_root = new Root();
					m_root.Database = this;
					m_root.Read(reader);
				}

				m_loaded = true;
			}
			catch (Exception ex)
			{
				throw new DatabaseException("Cannot load database." + ex.Message + " " + ex.StackTrace);
			}
			finally
			{
				if (stream != null)
					stream.Close();
			}
		}

		public override void Save(string fileName)
		{
			FileStream stream = null;
			try
			{
				stream = new FileStream(fileName, FileMode.Create, FileAccess.Write);
				using (BinaryWriter writer = new BinaryWriter(stream))
				{
					m_root.Write(writer);
				}
			}
			catch (Exception ex)
			{
				throw new DatabaseException("Cannot save database. " + ex.Message + " " + ex.StackTrace);
			}
		}

		public bool Loaded
		{
			get { return m_loaded; }
		}

		/// <summary>
		/// Try to get all info from id3
		/// </summary>
		/// <param name="fileName"></param>
		public void AddSong(string fileName)
		{
			TrackList list = m_root.GetNode<TrackList>();
			TrackItem item = TrackItem.Create("Urbans Title", "Urbans Album", "Urbans Artist");
			list.AddSong(item);
		}

		public TrackItem[] GetSongs()
		{
			 return m_songs.ToArray();
		}

		public string[] GetArtists()
		{
			return m_artists.ToArray();
		}

		public string[] GetAlbums()
		{
			return m_albums.ToArray();
		}

		public string[] GetAlbums(string artist)
		{
			if (m_artistAlbum.ContainsKey(artist))
				return m_artistAlbum[artist].ToArray();

			return new string[] { };
		}

		public TrackItem[] GetSongs(string album)
		{
			if (m_albumSongs.ContainsKey(album))
				return m_albumSongs[album].ToArray();

			return new TrackItem[] { };
		}

		public TrackItem[] GetAllSongs(string artist)
		{
			List<TrackItem> result = new List<TrackItem>();
			foreach (string album in GetAlbums(artist))
			{
				foreach (TrackItem song in GetSongs(album))
					result.Add(song);
			}

			return result.ToArray();
		}

		public TrackItem GetTrackItemFromTitle(string title)
		{
			foreach (TrackItem item in m_songs)
			{
				if (item.Title == null)
					continue;

				if (item.Title.StartsWith(title))
					return item;
			}

			return null;
		}

		public static string GetIPodRoot()
		{
			foreach (DriveInfo di in DriveInfo.GetDrives())
			{
				if (di.Name.StartsWith("a:") || di.Name.StartsWith("A:"))
					continue;

				if (File.Exists(di.Name + "iPod_Control\\iTunes\\iTunesDB"))
					return di.Name;
			}

			return string.Empty;
		}

		public void Clear()
		{
			m_songs.Clear();
			m_artists.Clear();
			m_albums.Clear();
			m_artistAlbum.Clear();
			m_albumSongs.Clear();

			m_root = null;
		}

		public override void AddNode(Node node)
		{
		}

		public override void RemoveNode(Node node)
		{
		}

		public override void RegisterNode(Node node)
		{
			TrackItem item = node as TrackItem;
			if (item != null)
				RegisterTrackItem(item);
		}

		private void RegisterTrackItem(TrackItem item)
		{
			m_songs.Add(item);

			if (item.Artist != null && !m_artists.Contains(item.Artist))
				m_artists.Add(item.Artist);

			if (item.Album != null && !m_albums.Contains(item.Album))
				m_albums.Add(item.Album);
			
			RegisterArtistAlbum(item);
			RegisterAlbumSong(item);
		}

		private void RegisterArtistAlbum(TrackItem item)
		{
			if (item.Artist == null || item.Album == null)
				return;

			List<string> albums = null;
			if (!m_artistAlbum.ContainsKey(item.Artist))
			{
				albums = new List<string>();
				m_artistAlbum.Add(item.Artist, albums);
			}
			else
				albums = m_artistAlbum[item.Artist];

			if (!albums.Contains(item.Album))
				albums.Add(item.Album);
		}

		private void RegisterAlbumSong(TrackItem item)
		{
			if (item.Album == null)
				return;

			List<TrackItem> songs = null;
			if (!m_albumSongs.ContainsKey(item.Album))
			{
				songs = new List<TrackItem>();
				m_albumSongs.Add(item.Album, songs);
			}
			else
				songs = m_albumSongs[item.Album];

			if (!songs.Contains(item))
				songs.Add(item);
		}
	}
}
